/**
 * \file CoachKernel.cpp
 *
 * Kernel implementation of the CoachKernel class
 */

#include "Coach/CoachKernel.h"
#include "Common/Tasks.h"
#include <stdio.h>
//#include <math.h>
//#include <string.h>
//#include <limits.h>

#include <string>
#include <fstream>

using namespace std;

#define MAX_PLAYER_AGE 15

// Konstruktor
CoachKernel::CoachKernel(const char* name /* = "CoachKernel"*/, const char* desc /* = "CoachKernel module"*/) : Module(name, desc, "v0.0.001")
{
	// Inicializacia simulacnych parametrov
	serverParams = NULL;
	playerParams = NULL;
	playerTypes = NULL;

	playMode = PM_BeforeKickOff;
	timeInPlayOn = 0;
	continousTimeInPlayOn = 0;
	canSendCLmessage = 0;
	sayCoachCnt = 0;
	scoreOur = 0;
	scoreTheir = 0;
	timeOfLastVisualInfo = 0;
	memset(&lastBallInfo, 0, sizeof(lastBallInfo));
	lastNearestPlayer = 0;
	memset(&lastKick, 0, sizeof(lastKick));
	FIFObottom = FIFOtop = 0;
	advice = 0;
	nHeteroCounter = 0;

	cornerKicksOur = 0;
	cornerKicksTheir = 0;
	offsidesOur = 0;
	offsidesTheir = 0;

	// Vsetci hraci su default typu
	memset(&playerTypesByNumber, 0, sizeof(playerTypesByNumber));

	// Zatial ziadna statistika 
	memset(&statsBall, 0, sizeof(statsBall));
	memset(statsOurPlayer, 0, 12 * sizeof(statsOurPlayer[0]));
	memset(statsTheirPlayer, 0, 12 * sizeof(statsTheirPlayer[0]));

	// Default adresar pre logo
	teamGraphicDir[0] = '\0';

	for(int i = 0; i < 32; i++)
		for(int j = 0; j < 8; j++)
			teamGraphicOk[i][j] = false;
	
	teamGraphicOkCount = 0;
	teamGraphicTries = 0;

	Main::GetInstance()->RegisterModule(this, MEMORY_TASK);
	Main::GetInstance()->RegisterModule(this, SYNCHRONIZATION_TASK);

	nZmenaTypov = 0;
}

// Destruktor
CoachKernel::~CoachKernel()
{
	int i, j;
	PLAYER_STATISTICS wholeTeam;
	
	ofstream out("Debug\\Timova statistika.txt"); // Zapis do suboru

	TXTN("   Cycles in play on mode: %d", timeInPlayOn);
	out << "   Cycles in play on mode: " << timeInPlayOn << endl;
	TXTN("  Cycles ball on our side: %d", statsBall.cyclesOnOurHalf);
	out << "  Cycles ball on our side: " << statsBall.cyclesOnOurHalf << endl;
	TXTN("Cycles ball on their side: %d", statsBall.cyclesOnTheirHalf);
	out << "Cycles ball on their side: " << statsBall.cyclesOnTheirHalf << endl;
	
	if(timeInPlayOn == 0)
		timeInPlayOn = 1;

	memset(&wholeTeam, 0, sizeof(wholeTeam));
	
	for(i = 1; i <= 11; i++)
	{
		if(statsOurPlayer[i].cyclesNearBall == 0) 
			statsOurPlayer[i].cyclesNearBall = 1;

		TXTN("Our player number %2d:", i);
		out << "Our player number: " << i << endl;
		TXTN(" - shoots on goal: %d", statsOurPlayer[i].shootsOnGoal);
		out << " - shoots on goal: " << statsOurPlayer[i].shootsOnGoal << endl;
		wholeTeam.shootsOnGoal += statsOurPlayer[i].shootsOnGoal;
		
		if(statsOurPlayer[i].shootsOnGoal > 0)
		{
			TXTN(" - average length of shoot: %.2lf", statsOurPlayer[i].sumLenShootsOnGoal / statsOurPlayer[i].shootsOnGoal);
			out << " - average length of shoot: " <<  statsOurPlayer[i].sumLenShootsOnGoal / statsOurPlayer[i].shootsOnGoal << endl;
			wholeTeam.sumLenShootsOnGoal += statsOurPlayer[i].sumLenShootsOnGoal;
		}

		TXTN(" - cycles with ball: %d", statsOurPlayer[i].cyclesWithBall);
		out << " - cycles with ball: " << statsOurPlayer[i].cyclesWithBall << endl;
		wholeTeam.cyclesWithBall += statsOurPlayer[i].cyclesWithBall;

		TXTN(" - average distance from ball (x): %f", statsOurPlayer[i].sumDistFromBall.GetX() / timeInPlayOn); 
		out << " - average distance from ball (x): " << statsOurPlayer[i].sumDistFromBall.GetX() / timeInPlayOn << endl;
		TXTN(" - average distance from ball (y): %f", statsOurPlayer[i].sumDistFromBall.GetY() / timeInPlayOn);
		out << " - average distance from ball (y): " << statsOurPlayer[i].sumDistFromBall.GetY() / timeInPlayOn << endl;
		wholeTeam.sumDistFromBall += statsOurPlayer[i].sumDistFromBall;

		TXTN(" - average speed near ball: %f", statsOurPlayer[i].sumSpeedNearBall / statsOurPlayer[i].cyclesNearBall);
		out << " - average speed near ball: " << statsOurPlayer[i].sumSpeedNearBall / statsOurPlayer[i].cyclesNearBall << endl;
		wholeTeam.sumSpeedNearBall += statsOurPlayer[i].sumSpeedNearBall;
		wholeTeam.cyclesNearBall += statsOurPlayer[i].cyclesNearBall;

		for(j = 0; j < PASS_LEN_COUNT; j++)
		{
			TXTN(" - number of all passes of length to %.1fm: %d", passLens[j], statsOurPlayer[i].passesAll[j]);		
			out << " - number of all passes of length to " << passLens[j] << ":" << statsOurPlayer[i].passesAll[j] << endl;		
			wholeTeam.passesAll[j] += statsOurPlayer[i].passesAll[j];
		}

		TXTN(" - number of all passes of length more than %.1fm: %d", passLens[j - 1], statsOurPlayer[i].passesAll[j]);	
		out << " - number of all passes of length more than: " << passLens[j - 1] << ":" << statsOurPlayer[i].passesAll[j] << endl;
		wholeTeam.passesAll[j] += statsOurPlayer[i].passesAll[j];

		for(j = 0; j < PASS_LEN_COUNT; j++)
		{
			TXTN(" - number of successful passes of length to %.1fm: %d", passLens[j], statsOurPlayer[i].passesSuccess[j]);		
			out << " - number of successful passes of length to: " << passLens[j] << ":" << statsOurPlayer[i].passesSuccess[j] << endl;		
			wholeTeam.passesSuccess[j] += statsOurPlayer[i].passesSuccess[j];
		}
		TXTN(" - number of successful passes of length more than %.1fm: %d", passLens[j - 1], statsOurPlayer[i].passesSuccess[j]);		
		out << " - number of successful passes of length to: " << passLens[j-1] << ":" << statsOurPlayer[i].passesSuccess[j] << endl;		
		wholeTeam.passesSuccess[j] += statsOurPlayer[i].passesSuccess[j];

//		TXTN(" - average length of successful passes: %f", 
//			statsOurPlayer[i].sumPassSucLen / statsOurPlayer[i].passesSuccess);
//		wholeTeam.sumPassSucLen += statsOurPlayer[i].sumPassSucLen;

		TXTN(" - number of received passes: %d", statsOurPlayer[i].passesReceived);
		out << " - number of received passes: " << statsOurPlayer[i].passesReceived << endl;
		wholeTeam.passesReceived += statsOurPlayer[i].passesReceived;

		TXTN(" - number of interceptions: %d", statsOurPlayer[i].interceptions);		
		out << " - number of interceptions: " << statsOurPlayer[i].interceptions << endl;		
		wholeTeam.interceptions += statsOurPlayer[i].interceptions;

		wholeTeam.cyclesAttacker += statsOurPlayer[i].cyclesAttacker;
		wholeTeam.cyclesDefender += statsOurPlayer[i].cyclesDefender;
		wholeTeam.cyclesMidfielder += statsOurPlayer[i].cyclesMidfielder;
	}
	
	TXTN("------------------------------------\nSummary for our team:");
	TXTN(" - shoots on goal: %d", wholeTeam.shootsOnGoal);
	
	if(wholeTeam.shootsOnGoal > 0)
	{
		TXTN(" - average length of shoot: %.2lf", wholeTeam.sumLenShootsOnGoal / wholeTeam.shootsOnGoal);
	}
	TXTN(" - cycles with ball: %d", wholeTeam.cyclesWithBall);
	TXTN(" - average speed near ball: %f", wholeTeam.sumSpeedNearBall / wholeTeam.cyclesNearBall);

	for(j = 0; j < PASS_LEN_COUNT; j++)
	{
		TXTN(" - number of all passes of length to %.1fm: %d", passLens[j], wholeTeam.passesAll[j]);
		TXTN(" - number of successful passes of length to %.1fm: %d", passLens[j], wholeTeam.passesSuccess[j]);
	}
	
	TXTN(" - number of all passes of length more than %.1fm: %d", passLens[j - 1], wholeTeam.passesAll[j]);
	TXTN(" - number of successful passes of length more than %.1fm: %d", passLens[j - 1], wholeTeam.passesSuccess[j]);

	TXTN(" - %% of successful passes for various lengths respectively:");
	
	for(j = 0; j <= PASS_LEN_COUNT; j++)
	{
		if(wholeTeam.passesAll[j] == 0)
			TXT("N/A ");
		else 
			TXT("%.2f ", (float)wholeTeam.passesSuccess[j] / wholeTeam.passesAll[j] * 100.0f);
	}
	TXTN("");

	TXTN(" - estimated number of defenders, midfielders and attackers, respectively:");
	TXTN("%.2f %.2f %.2f", (float)wholeTeam.cyclesDefender / timeInPlayOn, (float)wholeTeam.cyclesMidfielder / timeInPlayOn, 
		(float)wholeTeam.cyclesAttacker / timeInPlayOn);

	/*
	if(wholeTeam.passesSuccess == 0) 
		wholeTeam.passesSuccess = 1;
	TXTN(" - average length of successful passes: %f", 
		wholeTeam.sumPassSucLen / wholeTeam.passesSuccess);
*/
	TXTN(" - number of interceptions: %d", wholeTeam.interceptions);
	TXTN("------------------------------------");

	out << endl << endl;
				
	out << "----------------------" << endl;
	out << "Statistika nasho timu:" << endl;
	out << "----------------------" << endl << endl;
	
	out << "Pocet strelenych golov:	" << scoreOur << endl;
	out << "Pocet striel na branku:	" << wholeTeam.shootsOnGoal << endl;

	double nOurShootsSuccess = 0;

	if(wholeTeam.shootsOnGoal != 0)
		nOurShootsSuccess = (double) scoreOur / (double) wholeTeam.shootsOnGoal * 100;

	out << "Uspesnost striel (v %):	" << nOurShootsSuccess << endl;
	out << "Pocet rohovych kopov:	" << cornerKicksOur << endl;
	out << "Pocet ofsajdov:	" << offsidesOur << endl;
	
	int nAllOurPassesCount = 0, nAllTheirPassesCount = 0;
	int nAllOurPassesSuccess = 0, nAllTheirPassesSuccess = 0;
	int nOurInterceptions = 0, nTheirInterceptions = 0;
	int nOurCyclesWithBall = 0, nTheirCyclesWithBall = 0;

	for(i = 1; i <= 11; i++)
	{
		for(int j = 0; j <= PASS_LEN_COUNT; j++)
		{
			// Vsetky nahravky
			nAllOurPassesCount += statsOurPlayer[i].passesAll[j];
			nAllTheirPassesCount += statsTheirPlayer[i].passesAll[j];

			// Uspesne nahravky
			nAllOurPassesSuccess += statsOurPlayer[i].passesSuccess[j];
			nAllTheirPassesSuccess += statsTheirPlayer[i].passesSuccess[j];
		}

		// Zachytavanie prihravok
		nOurInterceptions += statsOurPlayer[i].interceptions;
		nTheirInterceptions += statsTheirPlayer[i].interceptions;

		// Drzanie lopty
		nOurCyclesWithBall += statsOurPlayer[i].cyclesWithBall;
		nTheirCyclesWithBall += statsTheirPlayer[i].cyclesWithBall;
	}
	
	double lfTmp;

	out << "Pocet prihravok:	" << nAllOurPassesCount << endl;
	
	lfTmp = (double) nAllOurPassesCount / (double) (nAllOurPassesCount + nAllTheirPassesCount) * 100;
	out << "Prihravanie (v %):	" << lfTmp << endl;

	lfTmp = (double) nAllOurPassesSuccess / (double) nAllOurPassesCount * 100;
	out << "Uspesnost prihravok (v %):	" << lfTmp << endl;

	out << "Pocet zachytenych prihravok:	" << nOurInterceptions << endl;
	
	lfTmp = (double) nOurInterceptions / (double) (nOurInterceptions + nTheirInterceptions) * 100;
	out << "Zachytavanie prihravok (v %):	" << lfTmp << endl;

	lfTmp = (double) nOurInterceptions / (double) nAllTheirPassesCount * 100;
	out << "Uspesnost zachytenia prihravok (v %):	" << lfTmp << endl;

	out << "Drzanie lopty (v cykloch):	" << nOurCyclesWithBall << endl;
	
	lfTmp = (double) nOurCyclesWithBall / (double) (nOurCyclesWithBall + nTheirCyclesWithBall) * 100;
	out << "Drzanie lopty (v %):	" << lfTmp << endl;
	
	memset(&wholeTeam, 0, sizeof(wholeTeam));
	
	for(i = 1; i <= 11; i++)
	{
		if(statsTheirPlayer[i].cyclesNearBall == 0) 
			statsTheirPlayer[i].cyclesNearBall = 1;

		TXTN("Their player number %2d:", i);
		out << "Their player number: " << i << endl;
		TXTN(" - shoots on goal: %d", statsTheirPlayer[i].shootsOnGoal);
		out << " - shoots on goal: " << statsTheirPlayer[i].shootsOnGoal << endl;
		wholeTeam.shootsOnGoal += statsTheirPlayer[i].shootsOnGoal;
		
		if(statsTheirPlayer[i].shootsOnGoal > 0)
		{
			TXTN(" - average length of shoot: %.2lf", statsTheirPlayer[i].sumLenShootsOnGoal / statsTheirPlayer[i].shootsOnGoal);
			out << " - average length of shoot: " << statsTheirPlayer[i].sumLenShootsOnGoal / statsTheirPlayer[i].shootsOnGoal << endl;
			wholeTeam.sumLenShootsOnGoal += statsTheirPlayer[i].sumLenShootsOnGoal;
		}

		TXTN(" - cycles with ball: %d", statsTheirPlayer[i].cyclesWithBall);
		out << " - cycles with ball: " << statsTheirPlayer[i].cyclesWithBall << endl;
		wholeTeam.cyclesWithBall += statsTheirPlayer[i].cyclesWithBall;

		TXTN(" - average distance from ball (x): %f", statsTheirPlayer[i].sumDistFromBall.GetX() / timeInPlayOn); 
		out << " - average distance from ball (x): " << statsTheirPlayer[i].sumDistFromBall.GetX() / timeInPlayOn << endl; 
		TXTN(" - average distance from ball (y): %f", statsTheirPlayer[i].sumDistFromBall.GetY() / timeInPlayOn);
		out << " - average distance from ball (y): " <<  statsTheirPlayer[i].sumDistFromBall.GetY() / timeInPlayOn << endl;
		wholeTeam.sumDistFromBall += statsTheirPlayer[i].sumDistFromBall;

		TXTN(" - average speed near ball: %f", statsTheirPlayer[i].sumSpeedNearBall / statsTheirPlayer[i].cyclesNearBall);
		out << " - average speed near ball: " << statsTheirPlayer[i].sumSpeedNearBall / statsTheirPlayer[i].cyclesNearBall << endl;
		wholeTeam.sumSpeedNearBall += statsTheirPlayer[i].sumSpeedNearBall;
		wholeTeam.cyclesNearBall += statsTheirPlayer[i].cyclesNearBall;

		for(j = 0; j < PASS_LEN_COUNT; j++)
		{
			TXTN(" - number of all passes of length to %.1fm: %d", passLens[j], statsTheirPlayer[i].passesAll[j]);
			out << " - number of all passes of length to " << passLens[j] << ":" << statsTheirPlayer[i].passesAll[j] << endl;
			wholeTeam.passesAll[j] += statsTheirPlayer[i].passesAll[j];
		}
		TXTN(" - number of all passes of length more than %.1fm: %d", passLens[j - 1], statsTheirPlayer[i].passesAll[j]);
		out << " - number of all passes of length more than " << passLens[j - 1] << ":" << statsTheirPlayer[i].passesAll[j] << endl;
		wholeTeam.passesAll[j] += statsTheirPlayer[i].passesAll[j];

		for(j = 0; j < PASS_LEN_COUNT; j++)
		{
			TXTN(" - number of successful passes of length to %.1fm: %d", passLens[j], statsTheirPlayer[i].passesSuccess[j]);
			out << " - number of successful passes of length to " << passLens[j] << ":" << statsTheirPlayer[i].passesSuccess[j] << endl;
			wholeTeam.passesSuccess[j] += statsTheirPlayer[i].passesSuccess[j];
		}
		TXTN(" - number of successful passes of length more than %.1fm: %d", passLens[j - 1], statsTheirPlayer[i].passesSuccess[j]);
		out << " - number of successful passes of length more than " << passLens[j - 1] << ":" << statsTheirPlayer[i].passesSuccess[j] << endl;
		wholeTeam.passesSuccess[j] += statsTheirPlayer[i].passesSuccess[j];

//		TXTN(" - average length of successful passes: %f", 
//			statsTheirPlayer[i].sumPassSucLen / statsTheirPlayer[i].passesSuccess);
//		wholeTeam.sumPassSucLen += statsTheirPlayer[i].sumPassSucLen;

		TXTN(" - number of received passes: %d", statsTheirPlayer[i].passesReceived);
		out << " - number of received passes: " << statsTheirPlayer[i].passesReceived << endl;
		wholeTeam.passesReceived += statsTheirPlayer[i].passesReceived;

		TXTN(" - number of interceptions: %d", statsTheirPlayer[i].interceptions);
		out << " - number of interceptions: " << statsTheirPlayer[i].interceptions << endl;
		wholeTeam.interceptions += statsTheirPlayer[i].interceptions;

		wholeTeam.cyclesAttacker += statsTheirPlayer[i].cyclesAttacker;
		wholeTeam.cyclesDefender += statsTheirPlayer[i].cyclesDefender;
		wholeTeam.cyclesMidfielder += statsTheirPlayer[i].cyclesMidfielder;
	}
	
	TXTN("------------------------------------\nSummary for their team:");
	TXTN(" - shoots on goal: %d", wholeTeam.shootsOnGoal);
	
	if(wholeTeam.shootsOnGoal > 0){
		TXTN(" - average length of shoot: %.2lf", wholeTeam.sumLenShootsOnGoal / wholeTeam.shootsOnGoal);
	}
	
	TXTN(" - cycles with ball: %d", wholeTeam.cyclesWithBall);
	TXTN(" - average speed near ball: %f", wholeTeam.sumSpeedNearBall / wholeTeam.cyclesNearBall);
	
	for(j = 0; j < PASS_LEN_COUNT; j++)
	{
		TXTN(" - number of all passes of length to %.1fm: %d", passLens[j], wholeTeam.passesAll[j]);
		TXTN(" - number of successful passes of length to %.1fm: %d", passLens[j], wholeTeam.passesSuccess[j]);
	}
	
	TXTN(" - number of all passes of length more than %.1fm: %d", passLens[j - 1], wholeTeam.passesAll[j]);
	TXTN(" - number of successful passes of length more than %.1fm: %d", passLens[j - 1], wholeTeam.passesSuccess[j]);
	TXTN(" - %% of successful passes for various lengths respectively:");
	
	for(j = 0; j <= PASS_LEN_COUNT; j++)
	{
		if(wholeTeam.passesAll[j] == 0)
			TXT("N/A ");
		else
			TXT("%.2f ", (float)wholeTeam.passesSuccess[j] / wholeTeam.passesAll[j] * 100.0f);
	}

	TXTN("");
	TXTN(" - estimated number of defenders, midfielders and attackers, respectively:");
	TXTN("%.2f %.2f %.2f", 
		(float)wholeTeam.cyclesDefender / timeInPlayOn, 
		(float)wholeTeam.cyclesMidfielder / timeInPlayOn, 
		(float)wholeTeam.cyclesAttacker / timeInPlayOn);

	/*
	if(wholeTeam.passesSuccess == 0) 
		wholeTeam.passesSuccess = 1;
	TXTN(" - average length of successful passes: %f", 
		wholeTeam.sumPassSucLen / wholeTeam.passesSuccess);
*/
	TXTN(" - number of interceptions: %d", wholeTeam.interceptions);

	// Pokracovanie statistiky u supera

	out << endl << endl;

	out << "--------------------------" << endl;
	out << "Statistika superovho timu:" << endl;
	out << "--------------------------" << endl << endl;

	out << "Pocet strelenych golov:	" << scoreTheir << endl;
	out << "Pocet striel na branku:	" << wholeTeam.shootsOnGoal << endl;

	double nTheirShootsSuccess = 0;

	if(wholeTeam.shootsOnGoal != 0)
		nTheirShootsSuccess = (double) scoreTheir / (double) wholeTeam.shootsOnGoal * 100;

	out << "Uspesnost striel (v %):	" << nTheirShootsSuccess << endl;
	out << "Pocet rohovych kopov:	" << cornerKicksTheir << endl;
	out << "Pocet ofsajdov:	" << offsidesTheir << endl;
		
	out << "Pocet prihravok:	" << nAllTheirPassesCount << endl;
	
	lfTmp = (double) nAllTheirPassesCount / (double) (nAllOurPassesCount + nAllTheirPassesCount) * 100;
	out << "Prihravanie (v %):	" << lfTmp << endl;

	lfTmp = (double) nAllTheirPassesSuccess / (double) nAllTheirPassesCount * 100;
	out << "Uspesnost prihravok (v %):	" << lfTmp << endl;

	out << "Pocet zachytenych prihravok:	" << nTheirInterceptions << endl;
	
	lfTmp = (double) nTheirInterceptions / (double) (nOurInterceptions + nTheirInterceptions) * 100;
	out << "Zachytavanie prihravok (v %):	" << lfTmp << endl;

	lfTmp = (double) nTheirInterceptions / (double) nAllOurPassesCount * 100;
	out << "Uspesnost zachytenia prihravok (v %):	" << lfTmp << endl;

	out << "Drzanie lopty (v cykloch):	" << nTheirCyclesWithBall << endl;
	
	lfTmp = (double) nTheirCyclesWithBall / (double) (nOurCyclesWithBall + nTheirCyclesWithBall) * 100;
	out << "Drzanie lopty (v %):	" << lfTmp << endl;

	out.close();

	// simulation parameters
	if(serverParams != NULL) delete serverParams;
	if(playerParams != NULL) delete playerParams;
	if(playerTypes != NULL) delete[] playerTypes;
}

// PROTECTED METODY

// Ak nie je mozne poslat spravu kvoli limitovanej komunikacii vrati sa 0, inak > 0
int CoachKernel::CanSendMessage()
{
	if(canSendCLmessage == 0)
		return 1;
	else // Mozme pouzit freeform spravu (???)
	{
		static int ffwp = serverParams->freeform_wait_period;
		// Cislo 3 je iba pre istotu
		if((sayCoachCnt < serverParams->say_coach_cnt_max) &&
		   (continousTimeInPlayOn / ffwp > 0) &&
		   (continousTimeInPlayOn % ffwp > 3) &&
		   (continousTimeInPlayOn % ffwp < serverParams->freeform_wait_period - 3))
		{
			return 2;
		}
	}

	return 0;
}

// Vrati ocakavanu formaciu timu
// param. our == true -> nasa formacia 
int CoachKernel::GetFormation(bool our)
{
	static float defs, mids, atts;
	static float min, lse; // least square error
	static int i, mini;

	atts = mids = defs = 0;
	if(our)
	{
		for(i = 1; i <= 11; i++)
		{
			atts += statsOurPlayer[i].cyclesAttacker;
			defs += statsOurPlayer[i].cyclesDefender;
			mids += statsOurPlayer[i].cyclesMidfielder;
		}
	}
	else
	{
		for(i = 1; i <= 11; i++)
		{
			atts += statsTheirPlayer[i].cyclesAttacker;
			defs += statsTheirPlayer[i].cyclesDefender;
			mids += statsTheirPlayer[i].cyclesMidfielder;
		}
	}
	defs = defs / timeInPlayOn;
	mids = mids / timeInPlayOn;
	atts = atts / timeInPlayOn;

	min = 1e10; // velke cislo
	mini = 0;
	for(i = 0; i < NUM_FORMATIONS; i++)
	{
		lse = (formation[i].defs - defs) * (formation[i].defs - defs) +
			(formation[i].mids - mids) * (formation[i].mids - mids) +
			(formation[i].atts - atts) * (formation[i].atts - atts);
		if(lse < min)
		{
			min = lse;
			mini = i;
		}
	}

	return mini;
}

// Je zastaveny simulacny cas?
bool CoachKernel::IsTimeStoped() const
{
	switch(GetPlayMode())
	{
	// Mody, ked je cas zastaveny
	case PM_BeforeKickOff:
	case PM_AfterGoal_Our:
	case PM_AfterGoal_Their:
		return true;
	default:
		// Simulacny cas bezi
		return false;
	}
}

// Posle spravu
void CoachKernel::SayMessage(const char* msg)
{
	static int i;

	// Posle prvu spravu vo FIFO bufferi
	if(msg == NULL)
	{ 
		if(FIFObottom != FIFOtop) // Buffer nie je prazdny
		{
			if((i = CanSendMessage()) > 0)
			{
				if(i == 2) // Mozme poslat freeform spravu
				{
					sayCoachCnt++;
					// TODO: musime modifikovat spravu na '(freeform "<message>")'
				}
				commandGen->Say(FIFObuffer[FIFObottom++]);
				
				if(FIFObottom > FIFO_BUFFER_SIZE)
					FIFObottom = 0;
				
				// +3 je pre istotu
				canSendCLmessage = serverParams->clang_win_size + 3;
			}
		}
	} 
	else // msg != NULL
	{
		if((i = CanSendMessage()) > 0) // Posli ju hned
		{
			if(i == 2) // Mozme poslat freeform spravu
			{
				sayCoachCnt++;
				// TODO: musime modifikovat spravu na '(freeform "<message>")'
			}
			commandGen->Say(msg);
			// +3 je pre istotu
			
			canSendCLmessage = serverParams->clang_win_size + 3;
		}
		else // Umiestni to do buffera
		{
			strcpy(FIFObuffer[FIFOtop++], msg);
			
			if(FIFOtop > FIFO_BUFFER_SIZE)
				FIFOtop = 0;
			
			if(FIFOtop == FIFObottom) // Buffer je plny
			{
				FIFObottom++;
				
				if(FIFObottom > FIFO_BUFFER_SIZE)
					FIFObottom = 0;
			}
		}
	}
}

static void XpmFree(char*** data, int lines)
{
	static int i;
	
	for(i = 0; i < lines; i++)
	{
		free((*data)[i]);
		(*data)[i] = NULL;
	}
	
	free(*data);
	*data = NULL;
}

static int XpmReadFileToData(const char* name, char*** data)
{
	FILE* fin;
	char c, pc, r[1000];
	int cnt, lines;
	bool commentInline, commentLong, quote;
	
	fin = fopen(name, "rt");
	
	if(fin == NULL)
		return -1;
	
	*data = NULL;
	commentInline = false;
	commentLong = false;
	quote = false;
	lines = 0;
	c = '\0';

	while(1)
	{
		pc = c;
		if(fscanf(fin, "%c", &c) != 1)
			break;
		
		if(quote)
		{
			if(c == '"' && pc != '\\')
			{
				quote = false;
				r[cnt] = '\0';
				lines++;

				*data = (char**) realloc(*data, lines * sizeof(char*));
				
				if(*data == NULL)
				{
					fclose(fin);
					return -2;
				}

				(*data)[lines - 1] = (char*) malloc((cnt + 1) * sizeof(char));
				
				if((*data)[lines - 1] == NULL)
				{
					fclose(fin);
					return -2;
				}

				strcpy((*data)[lines - 1], r);
			}
			else
			{
				if(c == '"' && pc == '\\')
					r[cnt - 1] = '"';
				else
					r[cnt++] = c;
			}
		}
		else if(commentLong)
		{
			if(c == '/' && pc == '*')
				commentLong = false;
		}
		else if(commentInline)
		{
			if(c == '\n')
				commentInline = false;
		}
		else
		{
			if(c == '"')
			{
				quote = true;
				cnt = 0;
			}
			if(c == '/' && pc == '/')
				commentInline = true;
			if(c == '*' && pc == '/')
				commentLong = true;
		}
	}

	fclose(fin);

	return lines;
}

// Posle logo na server
bool CoachKernel::SendTeamGraphic(const char* path)
{
	int i, j, k;
	char name[512];
	char msg[2048];
	char** data;

	// Ak uz sme poslali celu grafiku, nic nerob
	if(teamGraphicOkCount >= 256)
		return true;
	
	teamGraphicTries++;

	for(i = 0; i < 32; i++)
	{
		for(j = 0; j < 8; j++)
		{
			if(!teamGraphicOk[i][j])
			{
			    sprintf(name, "%slogo-%02i-%02i.xpm", path, i, j);
    
			    int rval = XpmReadFileToData(name, &data);
			    
				if(rval <= 0)
					return false;
    
			    int r, c, p, a;
			    
				if(sscanf(data[0], "%i %i %i %i", &r, &c, &p, &a) != 4)
					return false;
			    
				int lines = r + p + a;
    
			    msg[0] = '\0';
			    
				for(k = 0; k < lines; k++)
			    {
				    if(k != 0)
						strcat(msg, " ");
				   
					strcat(msg, "\"");
				    strcat(msg, data[k]);
				    strcat(msg, "\"");
			    }
    
			    XpmFree(&data, rval);
    
				if(msg[0] != '\0')
					(void) commandGen->TeamGraphic(i, j, msg);
				else
					return false;
			}
		}
	}

	return true;
}

// PUBLIC METODY

Interface* CoachKernel::GetInterface(int task) const
{
	if (task == MEMORY_TASK)
		return (CoachMemoryInterface*) this;
	else if (task == SYNCHRONIZATION_TASK)
		return (CoachSynchronizationInterface*) this;
	else
		return NULL;
}

int CoachKernel::Init(int argc, char** argv, int)
{
	for(int i = 1; i < argc; i++)
	{
		if(strcmp(argv[i], "-h") == 0)
		{
			fprintf(stderr, "\n%s %s switches\n\n", (char*) GetName(), (char*) GetVersion());
			fprintf(stderr, "\t-h: this help\n");
			fprintf(stderr, "\t-l <dir>: directory with team logo files\n\n");
			fprintf(stderr, "\t          <dir> HAS TO end with a slash/backslash, e.g.\n");
			fprintf(stderr, "\t          \"-l c:\\player\\logo\\\" or");
			fprintf(stderr, "\t          \"-l ~/player/logo\"");

			return INIT_ERR;
		}
		else if(strcmp(argv[i], "-l") == 0)
		{
			if(argv[++i] != NULL)
				strncpy(teamGraphicDir, argv[i], 512);
		}
	}

	return INIT_OK;
}

	// Handler pre spravy 'ok team_graphic'
void CoachKernel::OnOkTeamGraphic(int x, int y)
{
	teamGraphicOk[x][y] = true;
	teamGraphicOkCount++;
}

//
float CoachKernel::CalcRealSpeedMax(int type)
{
	PLAYER_TYPE* player_type = &playerTypes[type];
	float max_accel = 100.0f * player_type->dash_power_rate * player_type->effort_max;
    float real_speed_max = max_accel / (1.0f - player_type->player_decay);
    if ( real_speed_max > player_type->player_speed_max )
    {
        real_speed_max = player_type->player_speed_max;
    }
	return real_speed_max;
}

//
void CoachKernel::MakePlayerSelection()
{
	float curRealSpeedMax;
	float curDefIndex;
		
	int idForward = 0;
	int idDefense = 0;
	
	float stamina_inc_max = -1.0;
	float realSpeed = -1.0;
	float realDefIndex = -1.0;

  int i;

	for (i = 0; i < playerParams->player_types; i++)
	{
		curRealSpeedMax = CalcRealSpeedMax(i) ;
		
		if (realSpeed < curRealSpeedMax)
		{
			realSpeed = curRealSpeedMax;
			stamina_inc_max = playerTypes[i].stamina_inc_max;
			idForward = i;
		}
		else if (realSpeed == curRealSpeedMax && stamina_inc_max < playerTypes[i].stamina_inc_max)
		{
			realSpeed = curRealSpeedMax;
			stamina_inc_max = playerTypes[i].stamina_inc_max;
			idForward = i;
		}
	}

	for (i = 0; i < playerParams->player_types; i++)
	{
		if (i == idForward)
			continue;

		curRealSpeedMax = CalcRealSpeedMax(i);
		curDefIndex = curRealSpeedMax * this->playerTypes[i].kickable_margin;
		
		if (realDefIndex < curDefIndex)
		{
			realDefIndex = curDefIndex;
			stamina_inc_max = playerTypes[i].stamina_inc_max;
			idDefense = i;
		}
		else if (realDefIndex == curDefIndex && stamina_inc_max < playerTypes[i].stamina_inc_max)
		{
			realDefIndex = curDefIndex;
			stamina_inc_max = playerTypes[i].stamina_inc_max;
			idDefense= i;
		}
	}

	// nastavenie obrancov
	commandGen->ChangePlayerType(2, idDefense);	
	OnChangePlayerType(2, idDefense);
	commandGen->ChangePlayerType(3, idDefense);	
	OnChangePlayerType(3, idDefense);
	commandGen->ChangePlayerType(4, idDefense);	
	OnChangePlayerType(4, idDefense);
	
	// nastavenie utocnikov
	commandGen->ChangePlayerType(9, idForward);	
	OnChangePlayerType(9, idForward);
	commandGen->ChangePlayerType(10, idForward);	
	OnChangePlayerType(10, idForward);
	commandGen->ChangePlayerType(11, idForward);	
	OnChangePlayerType(11, idForward);
	TXTN("Zmena typov hracov");
}

